console.log(add) // [Function: add] 说明let声明的作用域没限制函数的声明 提升到了作用域的最顶部
console.log(foo) // [Function: foo]
{
  let x = 1
  function add(...values) {
    console.log(values) // [2, 5, 3]
    let sum = 0
    for (var val of values) {
      sum += val
    }
    console.log('sum', sum)
    return sum
  }
  add(2, 5, 3) // 10
}


{
  let obj = {
    a: 1,
    b: this.a,
    c: () => this.a
  }
  console.log(obj.b) // undefined
  console.log('obj.c', obj.c()) // undefined
}


{
  function consoA() {
    console.log(this.a)
  }
  consoA() // undefined
}


{
  function log(x, y = 'World') {
    console.log(x, y)
  }
  log('Hello') // Hello World
  log('Hello', 'China') // Hello China
  log('Hello', '') // Hello
}


// 参数默认值每次都重新计算默认值
{
  let x = 1
  function foo(p = x + 1) {
    console.log(p)
  }
  foo() // 2

  x = 100
  foo() // 101
}

// 与解构赋值默认值结合使用
{
  function fetch(url, { body = '', method = 'get', header = {} }) {
    console.log(method)
  }
  fetch('http://example.com', {}) // get
}
{
  // 双重默认值
  function fetch (url, {method = 'get'} = {}) {
    console.log('method', method)
  }
  fetch('http://example.com') // method get
}


{
  // 参数的默认值时空对象，但是设置了对象解构赋值
  function m1({ x = 0, y = 0 } = {}) {
    return [x, y]
  }
  // 参数的默认值时一个有具体属性的对象，但是没有设置对象解构赋值的默认值
  function m2({ x, y } = { x: 0, y: 0 }) {
    return [x, y]
  }
  console.log(m1({x: 3})) // [3, 0]
  console.log(m2({x: 3})) // [3, undefined]
  console.log(m1({})) // [0, 0]
  console.log(m2({})) // [undefined, undefined]
  console.log(m1({z: 3})) // [0, 0]
  console.log(m2({z: 3})) // [undefined]
}

// 作用域
{
  // 不设置默认参数的情况
  let x = 1
  function f(x, y) {
    console.log(y)
  }
  f(2) // undefined
}
{
  // 设置默认参数
  let x = 1
  function f(x, y = x) {
    console.log(y)
  }
  f(2) // 2
}
{
  // 设置默认参数
  let x = 1
  function f(y = x) {
    let x = 2
    console.log(y)
  }
  f() // 1  参数作用域种的x取得是最顶部的x
}

{
  // 默认参数是一个函数
  let foo = 'outer'
  function bar (func = x => foo) {
    let foo = 'inner'
    console.log(func())
  }
  bar() // outer
}

{
  function push (array, ...items) {
    items.forEach(function (item) {
      array.push(item)
      console.log(item)
    })
  }
  var a = []
  push (a, 1, 2, 3)
  console.log('a', a) // [1, 2, 3]
}
